﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Diagnostics;

namespace LowLevelGraphics.ColorSpaces
{
    /// <summary>
    /// CIELCH Color Space
    /// </summary>
    public enum CIELCHChannel
    {
        /// <summary>
        /// 
        /// </summary>
        L = 0,
        /// <summary>
        /// 
        /// </summary>
        C = 1,
        /// <summary>
        /// 
        /// </summary>
        H = 2
    }

    /// <summary>
    /// The cylindrical version of CIELUV is known as CIE LCHuv, where C* is the chroma and h is the hue
    /// </summary>
    [DebuggerDisplay("L: {m_L}, C: {m_C}, H: {m_H}")]
    public class CIELCH : AbstractColorSpace
    {
        protected double m_L = 0.0f;
        protected double m_C = 0.0f;
        protected double m_H = 0.0f;

        /// <summary>
        /// primary constructor
        /// </summary>
        /// <param name="_color"></param>
        public CIELCH(Color _color)
            :base(_color)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CIELCH"/> class.
        /// </summary>
        /// <param name="_L">The _ L.</param>
        /// <param name="_C">The _ C.</param>
        /// <param name="_H">The _ H.</param>
        public CIELCH(double _L, double _C, double _H)
        {
            m_L = _L;
            m_C = _C;
            m_H = _H;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CIELCH"/> class.
        /// </summary>
        internal CIELCH()
        {
        }

        /// <summary>
        /// used by clone to create a deep copy
        /// </summary>
        /// <param name="_cielch"></param>
        internal CIELCH(CIELCH _cielch)
        {
            this.m_Color = _cielch.m_Color;
            this.m_L = _cielch.m_L;
            this.m_C = _cielch.m_C;
            this.m_H = _cielch.m_H;
        }

        /// <summary>
        /// Enable casting into operator
        /// </summary>
        /// <param name="_color"></param>
        /// <returns></returns>
        public static explicit operator CIELCH(Color _color)
        {
            return new CIELCH(_color);
        }

        /// <summary>
        /// gets or sets l
        /// </summary>
        public double L
        {
            get { return m_L; }
            set { m_L = value; }
        }

        /// <summary>
        /// Gets or sets C
        /// </summary>
        public double C
        {
            get { return m_C; }
            set { m_C = value; }
        }

        /// <summary>
        /// Gets or sets h
        /// </summary>
        public double H
        {
            get { return m_H; }
            set { m_H = value; }
        }

        protected override void CalcValues()
        {
            CIELab cielab = new CIELab(m_Color);

            double var_H = Math.Atan2(cielab.b, cielab.a);  //Quadrant by signs

            if ( var_H > 0 ) var_H = ( var_H / Math.PI ) * 180;
            else             var_H = 360 - ( Math.Abs( var_H ) / Math.PI ) * 180;

            m_L = cielab.L;
            m_C = Math.Sqrt( cielab.a * cielab.a + cielab.b * cielab.b);
            m_H = var_H;
        }

        /// <summary>
        /// Back transformation to color
        /// </summary>
        /// <returns></returns>
        public override Color ToColor()
        {
            return new CIELuv(this.m_Color).ToColor();
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return string.Format("Color L = {0}, C = {1}, H = {2}", m_L, m_C, m_H);
        }

        /// <summary>
        /// Gets the values.
        /// </summary>
        /// <returns></returns>
        public override object[] GetValues()
        {
            return new object[] { m_L, m_C, m_H };
        }

        /// <summary>
        /// Sets the values.
        /// </summary>
        /// <param name="_aObject">The _a object.</param>
        public override void SetValues(object[] _aObject)
        {
            this.m_L = (double)_aObject[0];
            this.m_C = (double)_aObject[1];
            this.m_H = (double)_aObject[2];

        }

        /// <summary>
        /// used to create a deep copy
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new CIELCH(this);
        }
    }
}
